package com.ddm.server.common.redis;

import BaseCommon.CommLog;
import com.ddm.server.common.utils.BeanUtils;
import com.ddm.server.common.utils.GsonUtils;
import com.ddm.server.common.utils.MapUtils;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import net.sf.cglib.beans.BeanMap;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.*;

public class RedisMap2 implements Map<String, String> {

	private String sourceKey;

	RedisMap2(String sourceKey) {
		this.sourceKey = sourceKey;
	}

	@Override
	public void clear() {
		RedisUtil2.del(sourceKey);
	}

	@Override
	public boolean containsKey(Object key) {
		return RedisUtil2.hexists(sourceKey, key.toString());
	}

	@Override
	public boolean containsValue(Object value) {
		List<String> values = RedisUtil2.hvals(sourceKey);
		return values.contains(value);
	}

	@Override
	public Set<Entry<String, String>> entrySet() {
		return RedisUtil2.hgetAll(sourceKey).entrySet();
	}

	public Map<String, String> entryMapString() {
		return RedisUtil2.hgetAll(sourceKey);
	}

	public Map entryMap() {
		return RedisUtil2.hgetAllObject(sourceKey);
	}

	public  List<Entry<String, String>> listMap(Integer cursor, Integer size) {
		return RedisUtil2.hscan(sourceKey, cursor, size);
	}

	@Override
	public String get(Object key) {
		return RedisUtil2.hget(sourceKey, key.toString());
	}

	public <T> T getObject(Object key) {
		return RedisUtil2.hgetObject(sourceKey, key.toString());
	}

	public <T> T getObject(Object key, Class<T> clazz) {
		if(key != null){
			String result = get(String.valueOf(key));
			if(StringUtils.isNotEmpty(result)){
				Gson gson = new Gson();
				return gson.fromJson(result, clazz);
			}
		}
		return null;
	}

	@Override
	public boolean isEmpty() {
		return RedisUtil2.hlen(sourceKey) > 0;
	}

	public boolean isEmptyObject() {
		return RedisUtil2.hlenObject(sourceKey) > 0;
	}

	@Override
	public Set<String> keySet() {
		return RedisUtil2.hkeys(sourceKey);
	}

	@Override
	public String put(String key, String value) {
		if (value != null) {
			RedisUtil2.hset(sourceKey, key, value);
		} else {
			RedisUtil2.hdel(sourceKey, key);
		}
		return null;
	}

	public String putObject(String key, Object value) {
		if (value != null) {
			RedisUtil2.hsetObject(sourceKey, key, value);
		} else {
			RedisUtil2.hdelObject(sourceKey, key);
		}
		return null;
	}

	public String putJson(String key, Object value) {
		if(value != null){
			Gson gson =  new Gson();
			put(key, gson.toJson(value));
		}
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public void putAll(Map<? extends String, ? extends String> map) {
		if (map == null) {
			throw new NullPointerException();
		}
		if (map.size() == 0) {
			return;
		}
		RedisUtil2.hmset(sourceKey, (Map<String, String>)map);
	}

	public boolean putAllIf(Map<?, ?> m) {
		if(MapUtils.isEmpty(m)) {
			return false;
		}
		try {
			RedisUtil2.hmset(sourceKey, (Map<String, String>)m);
		} catch (Exception e){
			CommLog.error("RedisMap putAllIf map:{},message:{},e", m.toString(),e.getMessage(),e);
			return false;
		}
		return true;
	}


	@Override
	public String remove(Object key) {
		RedisUtil2.hdel(sourceKey, key.toString());
		return null;
	}

	public String removeObject(Object key) {
		RedisUtil2.hdelObject(sourceKey, key.toString());
		return null;
	}

	@Override
	public int size() {
		return (int)RedisUtil2.hlen(sourceKey);
	}

	public int sizeObject() {
		return (int)RedisUtil2.hlenObject(sourceKey);
	}

	@Override
	public Collection<String> values() {
		return RedisUtil2.hvals(sourceKey);
	}

	@Override
	public String toString() {
		return RedisUtil2.hgetAll(sourceKey).toString();
	}

	public Map<String,String> toMap() {
		Map<String,String> map = Maps.newHashMap();
		for (Entry<String, String> entry : this.entrySet()) {
			map.put(entry.getKey().toString(), entry.getValue().toString());
		}
		return map;
	}

	/**
	 * 获取一个实体
	 * @param key
	 * @param <T>
	 * @return
	 */
	public <T> T getBean(String key, Class<T> classOfT) {
		String o  = this.get(key);
		return Objects.nonNull(o) && StringUtils.isNotEmpty(o) ? GsonUtils.stringToBean(o.trim(), classOfT):null;
	}

	public boolean putIf(String key, String value) {
		try {
			RedisUtil2.hset(sourceKey, key, value);
		} catch (Exception e){
			CommLog.error("RedisMap putIf key:{},value:{},message:{},e", key,value,e.getMessage(),e);
			return false;
		}
		return true;
	}


	/**
	 * 将对象转换为map
	 *
	 * @param bean
	 * @return
	 */
	public <T> boolean beanToMap(T bean) {
		Map<String, Object> map = Maps.newHashMap();
		BeanMap beanMap = BeanMap.create(bean);
		for (Object key : beanMap.keySet()) {
			Object o  = BeanUtils.getObjDefault(beanMap.get(key));
			if (Objects.nonNull(o)) {
				map.put(key.toString(), String.valueOf(o));
			}
		}
		if (MapUtils.isNotEmpty(map)) {
			return this.putAllIf(map);
		}
		return false;
	}



	/**
	 * 将Map对象通过反射机制转换成Bean对象
	 *
	 * @param clazz 待转换的class
	 * @return 转换后的Bean对象
	 * @throws Exception 异常
	 *                   异常暂时保留
	 */
	public <T> T mapToBean(Class<T> clazz) {
		try {
			if (this.size() > 0) {
				T obj = clazz.newInstance();
				for (Entry<String, String> entry : this.entrySet()) {
					//属性名
					String propertyName = entry.getKey().toString();
					Object value = entry.getValue();
					String setMethodName = "set"
							+ propertyName.substring(0, 1).toUpperCase()
							+ propertyName.substring(1);
					Field field = BeanUtils.getClassField(clazz, propertyName);
					if (field == null) {
						continue;
					}
					Class<?> fieldTypeClass = field.getType();
					value = BeanUtils.convertValType(value, fieldTypeClass,field.getGenericType());
					clazz.getMethod(setMethodName, field.getType()).invoke(obj, value);
				}
				return obj;
			}
		} catch (Exception e) {
			CommLog.error("mapToBean error:{}",e.getMessage(),e );
		}
		return null;
	}
}
